Features new to VirtualDub 1.4 |
VirtualDub 1.4 contains a couple incremental changes to the filter SDK you might be interested in. If you want to use these extensions, but don't want to break compatibility with VirtualDub 1.2, you can do so by checking the vdfd_ver flag passed to your DLL's initialization function. This value is 4 for V1.2, 5 for V1.3d, 6 for V1.4, and 7 for V1.4d. By default, the sample init function given in the tutorial allows your filter to run under V1.2, so you will want to explicitly hardcode 6 in the return value if you need to use V1.4 functionality.
Exception handling (VirtualDub 1.4 / API V6) |
The recommended course of action for VirtualDub 1.3 filters when failing a filter init or start is to return a non-zero value. Obviously, this is not very descriptive and leads to user confusion when a filter fails. Starting with VirtualDub 1.4, there are two new functions in the SDK in the FilterFunctions structure:
void (*ExceptOutOfMemory)();
void (*Except)(const char *format, ...);
The first is simple: you call it when you run out of memory. The second allows you to throw any descriptive error string, although keep it short please (<128 bytes is good). Both functions will abort your code by throwing a C++ exception back, so unless your code is simple enough to not require any exception handling, it is recommended that you either wrap code in try { } catch(...) { } handlers to clean up along the way, or implement your own exception handling and throw VirtualDub's exception at the end of the filter function.
You can only use these functions from within initProc, startProc, and runProc. Throwing exceptions anywhere else will cause crashes.
CPU detection (VirtualDub 1.4 / API V6) |
VirtualDub 1.4 has vastly better CPU detection over previous versions. The third new function in FilterFunctions is getCPUFlags(). This function returns a bitfield which states all the CPU extensions you are allowed to use:
This flag tells you if the user has a really crappy CPU or not.
Windows supports FPU emulation for all systems, so you may safely use FPU instructions regardless. However, this flag tells you if you should do FPU-specific optimizations. Since there is only one CPU for which this is even faintly feasible, the Pentium, you can usually ignore this flag. (The Pentium is an oddball in that a floating-point multiply is more than three times faster than an integer one.)
This is the biggie. Pay attention to this flag, since MMX is a huge improvement over regular scalar code, mainly due to the extra registers.
This flag indicates that the CPU supports the subset of Intel's Streaming SIMD Extensions that only uses MMX registers. Among the instructions included are pshufw, pavgb, and pavgw. This flag is set for Pentium III and Athlon CPUs. AMD literature labels these instructions as "MMX extensions," and it is also sometimes referred to as MMX2.
This flag indicates that the CPU supports the entire SSE instruction set, including the XMM registers. Athlon CPUs will have this flag clear, while it is set for Pentium III CPUs.
This flag indicates that the SSE2 instruction set, available first in the Pentium 4, can be used.
If this appears, the CPU has support for AMD's 3DNow! extensions.
The CPU has support for the AMD 3DNow! extensions which appeared with the Athlon.
Reusing the stack pointer (VirtualDub 1.4 / API V6) |
In the Win32 environment, it is possible to change ESP away from the stack, because interrupts do not occur on the user-mode stack. Although it is still recommended that you bump ESP down before accessing stack automatics, ESP can used to point to other data. VirtualDub 1.4 provides a way to do this while still allowing reentrancy; it is possible to code a routine that reuses ESP while being run concurrently on different threads. To do this, the entire routine should be written in assembly language.
When VirtualDub starts a thread, it initializes the application dword at fs:[14h] to a thread-specific data structure. The first 68 bytes of this structure are reserved for functions that wish to reuse ESP, with the top four bytes used for ESP itself. That means, to reuse ESP, you should code as follows:
mov eax,dword ptr fs:[14h] ;[move stack values into thread-specific space] mov dword ptr [eax+40h],esp mov esp,new_value ... mov eax,dword ptr fs:[14h] mov esp,dword ptr [eax+40h]
All values in the first 64 bytes pointed to by fs:[14h] should be considered forfeit as soon as you jump away from the current function in any way; this includes calling VirtualDub functions or returning from filter functions. You should not store non-constant values for your inner loop in global variables, as this will make your routine non-reentrant. If you need to use absolute addressing, copy the code block to a new memory area and relocate the addresses to new locations. Also, do not call any VirtualDub functions with ESP set away from the normal stack -- you may derail exception handling if you do so. Finally, never modify fs:[14h] under any circumstances.
Be aware that debugging a routine that modifies ESP may inhibit your ability to debug the routine. You should attempt to optimize the routine with a regular stack pointer before freeing up ESP for an 8th register.
![]() |
![]() fs:[14h] is reserved for the current application, so this feature is unavailable when running under Avisynth. |
Host version query and filter lag (VirtualDub 1.4d / API V7) |
The FilterFunctions structure now contains a new member:
long (*getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d)
This function returns the host version string in the buffer you supply, and the build number directly. The host version string should be in this format:
program-name version (build) by author
With VirtualDub, this string is the same as the initial title bar string on startup.
![]() |
![]() Check for the presence of the string "VirtualDub" before relying on the build number. There are derivatives of VirtualDub that have invalid build numbers (0) or have restarted their own build number sequence (Nandub). |
The second new feature in API V7 is the ability to set a lag value for a filter. This is done by or'ing a lag value onto the high 16-bits of the value returned by a filter's paramProc function. You can do this easily with the macro FILTERPARAM_HAS_LAG:
return FILTERPARAM_HAS_LAG(8) + FILTERPARAM_SWAP_BUFFERS;
This doesn't change the way your filter is called, but it causes VirtualDub to delay audio sync to compensate. Your filter is responsible for lagging its output by the indicated number of frames. At the end of the clip, VirtualDub will repeat the last frame until the lag is cleared.
![]() |
![]() Avisynth, and VirtualDub's capture and frameserver modes, do not support lag, so using this feature will limit the applicability of your filter. |
VirtualDub external filter SDK 1.05 | ©1999-2001 Avery Lee <phaeron@virtualdub.org> |